#include <GL/glew.h>
#include <GL/glut.h>

#include <vector>
#include "SweepSurf.h"

using namespace std;

void loadSurfaces();
void drawSurfaces();
void addAxis();

void keyboard(unsigned char,int,int);
void handleResize(int,int);
void initlights(void);
void drawScene();

vector<float>* createPoints();
vector<float>* createPath();
void addPoint(vector<float>*,float,float,float);

void freeMem();

float windowWidth  = 800.0f;
float windowHeight = 600.0f;

GLfloat rotx = 0.0;
GLfloat roty = 0.0;
GLfloat rotz = 0.0;

SweepSurf* sweep;

int main(int argc, char** argv) {
 //Initialize GLUT
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
 glutInitWindowSize(windowWidth,windowHeight);
	
 //Create the window
 glutCreateWindow("Project");
 glEnable(GL_DEPTH_TEST);
	
 //Set handler functions
 glutDisplayFunc(drawScene);		// drawing function
 glutKeyboardFunc(keyboard);		// keyboard function
 glutReshapeFunc(handleResize);		// for reshaping the window		 

 loadSurfaces();
 initlights();

 // Main Loop  
 glutMainLoop();
 return 0;
}

void initlights(void)
{
/* 
   GLfloat ambient[] = {0.2, 0.2, 0.2, 1.0};
   GLfloat position[] = {0.0, 0.0, 2.0, 1.0};
   GLfloat mat_diffuse[] = {0.6, 0.6, 0.6, 1.0};
   GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
   GLfloat mat_shininess[] = {50.0};

   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);

   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
   glLightfv(GL_LIGHT0, GL_POSITION, position);

   glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
*/
}

//Called when the window is resized
void handleResize(int w, int h) {
 glViewport(0, 0, w, h);
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 gluPerspective(45.0, (double)w / (double)h, 1.0, 200.0);
}

//Draws the 3D scene
void drawScene() {
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective

 drawSurfaces();
 glutSwapBuffers();
}

float alfa = 0;
void keyboard(unsigned char key, int x, int y)
{
 switch (key) {
   case 'x':
   case 'X':
      rotx = rotx - 10.0f;
      glutPostRedisplay();
      break;
   case 's':
   case 'S':
      rotx = rotx + 10.0f;
      glutPostRedisplay();
      break;
   case 'y':
   case 'Y':
      roty = roty + 10.0f;
      glutPostRedisplay();
      break;
   case 't':
   case 'T':
      roty = roty - 10.0f;
      glutPostRedisplay();
      break;
   case 'a':
   case 'A':
      rotz = rotz - 10.0f;
      glutPostRedisplay();
      break;
   case 'z':
   case 'Z':
      rotz = rotz + 10.0f;
      glutPostRedisplay();
      break;
   case 27:
      freeMem();
      exit(0);
      break;
   }
}

// curvas
// ------------------------------------------------------------------
void loadSurfaces(){
 sweep  = new SweepSurf(createPoints(),createPath());
}

 vector<float>* createPoints(){
 vector<float>* PuntosControl = new vector<float>();

 int e=1;

 addPoint(PuntosControl,    0*e,  -1*e, 0);
 addPoint(PuntosControl,    1*e,  -1*e, 0);
 addPoint(PuntosControl,    1*e,   0*e, 0);
 addPoint(PuntosControl,    1*e,   1*e, 0);
 addPoint(PuntosControl,  0.5*e,   1*e, 0);
 addPoint(PuntosControl,  0.5*e, 1.5*e, 0);
 addPoint(PuntosControl,    1*e,   2*e, 0);
 addPoint(PuntosControl,    0*e,   2*e, 0);

 addPoint(PuntosControl,    0*e,   2*e, 0);
 addPoint(PuntosControl,    0*e,   2*e, 0);
 addPoint(PuntosControl,   -1*e,   2*e, 0);
 addPoint(PuntosControl, -0.5*e, 1.5*e, 0);
 addPoint(PuntosControl, -0.5*e,   1*e, 0);
 addPoint(PuntosControl,   -1*e,   1*e, 0);
 addPoint(PuntosControl,   -1*e,   0*e, 0);
 addPoint(PuntosControl,   -1*e,  -1*e, 0);
 addPoint(PuntosControl,    0*e,  -1*e, 0);

 return PuntosControl;
}

vector<float>* createPath(){
 vector<float>* PuntosControl = new vector<float>();

 float a = 0;
 float b = 5;
 for (int i=0; i<25;i++){
 	addPoint(PuntosControl,0,b*sin(a),i);
	a+=0.5;
 }
 return PuntosControl;
}

void addPoint(vector<float>* vector,float x,float y, float z){
	vector->push_back(x);
	vector->push_back(y);
	vector->push_back(z);
}

void drawSurfaces(){

 glLoadIdentity(); 
 glTranslatef(-4.0f, 0.0f, -50.0f);
 glRotatef(rotx, 1.0, 0.0, 0.0);
 glRotatef(roty, 0.0, 1.0, 0.0);
 glRotatef(rotz, 0.0, 0.0, 1.0);

 glColor3f(1.0f,1.0f,1.0f);
 addAxis();

 glColor3f(1.0f,0.0f,0.0f);
 //sweep->drawControlPoints();

 glColor3f(1.0f,0.0f,1.0f);
 sweep->drawPath(glm::mat4(1.0));

 glColor3f(1.0f,0.0f,0.0f);
 sweep->drawSurface(glm::mat4(1.0));
// glColor3f(1.0f,1.0f,0.0f);
// sweep->drawNormals(glm::mat4(1.0));
}

void addAxis(){
 glBegin(GL_LINE_LOOP);
 	glVertex3f(-100.0f,0.0f,-1.0f);
 	glVertex3f(100.0f,0.0f,-1.0f);
 glEnd();

 glBegin(GL_LINE_LOOP);
 	glVertex3f(0.0f,-100.0f,-1.0f);
 	glVertex3f(0.0f,100.0f,-1.0f);
 glEnd();

}

void freeMem(){
 delete(sweep);
}
